/*
 * libsyscalls.c
 *
 *  Created on: Oct 8, 2009
 *      Author: artur
 */

#define SYSCALL_INT	0xFD

#define __SCN_end			0
#define __SCN_putchar	1
#define __SCN_remap	2


__inline__ unsigned int remap(unsigned int _a, int _s)
{
	volatile register unsigned int __res;
	__asm__ volatile (
			"int $0xFD"
			: "=a" (__res)
			: "a" ((unsigned int)(__SCN_remap)),"b" ((unsigned int)(_a)), "c" ((int)(_s))
			);

	return (unsigned int) __res;
}

__inline__ unsigned int putchar(char c)
{
	volatile register unsigned int __res;
	__asm__ volatile (
			"int $0xFD"
			: "=a" (__res)
			: "a" ((unsigned int)(__SCN_putchar)),"b" ((unsigned int)(c))
			);

	return (unsigned int) __res;
}

/**
 * s - portnum
 */
__inline__ void	outl(unsigned int s, unsigned int t)
{
	__asm__ volatile (
			"outl %%eax,%%dx"
			:
			: "a" ((unsigned int)(s)),"d" ((unsigned int)(t))
			);
}

/**
 * s - portnum
 */
__inline__ void	outw(unsigned short s, unsigned int t)
{
	__asm__ volatile (
			"outw %%ax,%%dx"
			:
			: "a" ((unsigned short)(s)),"d" ((unsigned int)(t))
			);
}
/**
 * s - portnum
 */
__inline__ void	outb(unsigned char s, unsigned int t)
{
	__asm__ volatile (
			"outb %%al,%%dx"
			:
			: "a" ((unsigned char)(s)),"d" ((unsigned int)(t))
			);
}

/**
 *
 */
__inline__ unsigned int inl(unsigned int s)
{
	volatile register unsigned int __res;
	__asm__ volatile (
			"inl %%dx,%%eax"
			: "=a" (__res)
			: "d" ((unsigned int)(s))
			);
	return (unsigned int) __res;
}

/**
 *
 */
__inline__ unsigned short inw(unsigned int s)
{
	volatile register unsigned short __res;
	__asm__ volatile (
			"inw %%dx,%%ax"
			: "=a" (__res)
			: "d" ((unsigned int)(s))
			);
	return (unsigned short) __res;
}

/**
 *
 */
__inline__ unsigned char inb(unsigned int s)
{
	volatile register unsigned char __res;
	__asm__ volatile (
			"inb %%dx,%%al"
			: "=a" (__res)
			: "d" ((unsigned int)(s))
			);
	return (unsigned char) __res;
}

/**
 *
 */
void itoa(char *buf, int base, int d)
{
	char *p = buf;
	char *p1, *p2;
	unsigned long ud = d;
	int divisor = 10;

	if (base == 'd' && d < 0) {
		*p++ = '-';
		buf++;
		ud = -d;
	} else if (base == 'x')
		divisor = 16;

	do {
		int remainder = ud % divisor;
		*p++ = (remainder < 10) ? remainder + '0' : remainder + 'a' - 10;
	} while (ud /= divisor);

	*p = 0;

	p1 = buf;
	p2 = p - 1;
	while (p1 < p2) {
		char tmp = *p1;
		*p1 = *p2;
		*p2 = tmp;
		p1++;
		p2--;
	}
}

/**
 *
 */
void printf(const char *format, ...)
{
	char **arg = (char **) &format;
	char c;
	char buf[20];

	arg++;

	while ((c = *format++) != 0) {
		if (c != '%')
		{
			putchar(c);
		}
		else {
			char *p;

			c = *format++;
			switch (c) {
			case 'd':
			case 'u':
			case 'x':
				itoa(buf, c, *((int *) arg++));
				p = buf;
				goto string;
				break;

			case 's':
				p = *arg++;
				if (!p)
					p = "(null)";

				string: while (*p)
					putchar(*p++);
				break;

			default:
				putchar(*((int *) arg++));
				break;
			}
		}
	}

}
